#include "mythread.h"
#include "global.h"
#include <QMainWindow>
#include <QEventLoop>
#include <QMessageBox>
#include <QHostInfo>
#include <QLabel>
#include <QTimer>
#include <QDialog>

MyThread::MyThread(qintptr socketDescriptor, QObject *parent):
    QThread(parent)
{
    socket = new QTcpSocket();  // 不要指定父指针，否则会出现 moveToThread说的错误
    socket->setSocketDescriptor(socketDescriptor);
    socket->moveToThread(this); //如果不调用此函数，将报如下错误

    /*
        QObject: Cannot create children for a parent that is in a different thread.
        (Parent is QNativeSocketEngine(0x2ada62e0), parent's thread is QThread(0x946fb0), current thread is QThread(0x2ad968c0)
    */

    connect(socket, &QTcpSocket::readyRead, this, &MyThread::onReadyRead);  // 一定要这样写！！！
}


void MyThread::run()
{

    lock.lockForRead();
    QByteArray data;
    for(int i=0;i!=listItem.count();++i){
        data.append(listItem.at(i));
    }
    lock.unlock();
    socket->write(data,data.size());


    /*
        子线程中不能阻塞主循环。
        在子线程中无法阻塞主循环，而 while(!killThread){msleep(2000);} 会一直占用线程资源，导致无法响应其他任务。
        正确的写法是使用 QEventLoop 并在循环中使用 processEvents() 强制处理队列中的事件，在此基础上使用 msleep() 实现周期性的暂停。
        在 processEvents() 中传入 QEventLoop::AllEvents 参数可以确保能够处理所有类型的事件。
        需要注意的是，如果在循环中出现了问题导致程序无法正常结束，可以通过 processEvents() 的第二个参数来设置最长等待时间，以免导致线程一直无法退出。
    */

    QEventLoop loop;
    while(!killThread){
        loop.processEvents(QEventLoop::AllEvents, 7000); // 如果不加这条语句，会一直占用线程资源，这样上面socket写的数据也将无法发送
    }

    timer->stop();  // 停止定时器
    delete aSession;    // 释放会话

    socket->close();    // 关闭socket
    emit closeThread(this); // 发送信号通知主线程结束对应子线
    emit updateListItem();

    MyThread::exit();
}

void MyThread::onReadyRead()
{
    QString data;

    while(socket->canReadLine()){
        data = socket->readAll();
    }
    data.chop(1);

    QString type = data.split(';').at(0);
    QString item = data.split(';').at(1);

    tcpMsgType msgType;
    if(type == "UserEnter") msgType = UserEnter;
    else if(type == "UserLeft") msgType = UserLeft;
    else msgType = KeepAlivePacket; // 心跳包

    lock.lockForWrite();
    switch(msgType){
    case UserEnter:{
        listItem.append(item);
        currentItem = item;
        QDateTime dateTime = QDateTime::currentDateTime();
        aSession = new Session(item,dateTime);


        timer = new QTimer(this);
        connect(timer,&QTimer::timeout,this,[&](){
            bool mark = aSession->isKeepAlive(QTime::currentTime());
            if(!mark){
                removeItem(currentItem);
                killThread = true;
            }
        });
        timer->start(5000);
        emit updateListItem();
    }
        break;
    case UserLeft:
        removeItem(item);
        killThread = true;
        break;
    case KeepAlivePacket:
        aSession->updateDateTime(QDateTime::currentDateTime());    // 更新会话的最新时间戳
        break;
    }
    lock.unlock();    
}

void MyThread::removeItem(const QString &item)
{
    for(int i=0;i<listItem.count();++i){
        if(listItem.at(i) == item){
            listItem.removeAt(i);
            break;
        }
    }
}


